/*
 * Ucache: Userspace Cache Filesystem
 * Copyright (C) 2013 Will Dignazio
 */

#include "internal.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

static UCache* ucache;
static UCacheArgs ucache_args = { "", MEMORY_MAX_DEFAULT, 2, false };
static UCacheOps ucache_ops = {
	.getattr	= fuse_fgetattr,
	.readdir	= fuse_freaddir,
	.create		= fuse_create,
};

UCache*
getinstance(void)
{

	return ucache;
}

UCache*
ucache_init(Error *err)
{
	Disk* disk;
	int ret;

	ucache = NULL;

	ucache = calloc(1, sizeof(UCache));
	if(ucache == NULL)
		goto fail;

	/*
	 * It's largely important that this be one of if
	 * not the first things done to the ucache. Alot
	 * of the initialization and usage functions rely
	 * on the parameters of the ucache args.
	 */
	ucache->args = &ucache_args;

	ret = disk_open("ucachefs_ldb", &disk, err);
	if(ret != 0)
		goto fail;

	ucache->mem_alloced = 0;
	ucache->mem_max = ucache_args.memrange;

	ret = umdb_open(ucache, err);
	if(ret != 0)
		error(err, "Failed to open ucache database: %d", ret);

	return ucache;

fail:
	if(ucache != NULL)
		free(ucache);

	return NULL;
}

static struct fuse_opt fuse_opts[] = {
	UCACHE_OPT("mountpoint=%s", mountpoint, 0),
	UCACHE_OPT("memrange=%s", memrange, MEMORY_MAX_DEFAULT),
	UCACHE_OPT("nodesz=%s", nodesz, 2),
	UCACHE_OPT("verbose=%d", verbose, 0),
	FUSE_OPT_END
};

static int
fuseopt_parse(void* data, const char* arg, int key, struct fuse_args *outargs)
{
	switch(key)
	{
	case FUSE_OPT_KEY_NONOPT:
		if(*ucache_args.mountpoint == '\0')
			ucache_args.mountpoint = strdup(arg);
		return 1;
	case FUSE_OPT_KEY_OPT:
		break;
	default:
		fprintf(stderr, "Error parsing ucache args, exiting.\n");
		exit(1);
		break;
	};

	return 0;
}

int
main(int argc, char* argv[])
{
	UCache* ucache;
	Error err;
	int r;

	struct fuse_args farguments = FUSE_ARGS_INIT(argc, argv);
	r = 0;

	fprintf(stdout, "Initializing fuse options.\n");
	fuse_opt_parse(&farguments, &ucache_args, fuse_opts, fuseopt_parse);

	fprintf(stdout, "Initializing ucache instance.\n");
	ucache = ucache_init(&err);

	fprintf(stdout, "Initializing FUSE itnerface.\n");
	r = fuse_main(farguments.argc, farguments.argv, &ucache_ops, NULL);
	fuse_opt_free_args(&farguments);

	printf("%s\n", strerror(r));
	return r;
}
